/*
 * @(#)WorkflowTriggerScheduleJob.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */

package com.dcivision.workflow.core;

import java.sql.Connection;
import java.sql.Timestamp;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionException;

import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.DataSourceFactory;
import com.dcivision.framework.ErrorConstant;
import com.dcivision.framework.EventLogger;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.MessageResourcesFactory;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.SystemFunctionConstant;
import com.dcivision.framework.TextUtility;
import com.dcivision.framework.Utility;
import com.dcivision.user.bean.UserRecord;
import com.dcivision.user.dao.UserRecordDAObject;
import com.dcivision.workflow.WorkflowErrorConstant;
import com.dcivision.workflow.bean.WorkflowProgress;
import com.dcivision.workflow.bean.WorkflowRecord;
import com.dcivision.workflow.bean.WorkflowSchedule;
import com.dcivision.workflow.bean.WorkflowScheduleTriggers;
import com.dcivision.workflow.bean.WorkflowTriggersLog;
import com.dcivision.workflow.dao.WorkflowRecordDAObject;
import com.dcivision.workflow.dao.WorkflowScheduleTriggersDAObject;
import com.dcivision.workflow.dao.WorkflowTriggersLogDAObject;
import com.dcivision.workflow.web.MaintWorkflowRecordForm;
/**
 * WorkflowTriggerScheduleJob.java
 *
 * This class is the WorkflowTriggerScheduleJob
 *
 * @author Tony Chen
 * @company DCIVision Limited
 * @creation date 28/12/2004
 * @version $Revision: 1.9.2.1 $
 */

public class WorkflowTriggerScheduleJob implements Job {
  protected Log log = LogFactory.getLog(this.getClass().getName());
  
  private SessionContainer sessionContainer = null;
  private Connection dbConn = null;
  
  private String objectID = null;
  
  /** Creates a new instance of SchedulerTest */
  public WorkflowTriggerScheduleJob() {
    
  }
  /**
   * Executes this job
   * @param context The JobExecutionContext object
   * @throws JobExecutionException
   */
  public void execute(org.quartz.JobExecutionContext context) throws org.quartz.JobExecutionException {
    JobDataMap dataMap = context.getJobDetail().getJobDataMap();
    log.debug("##################################################");
    log.debug("ObjectID: "+ dataMap.getString("objectID"));
    this.objectID = dataMap.getString("objectID");
    
    log.debug("===================== Start A Workflow Begin.===========================");
    Integer trigerEventUserID = new Integer(0);
    String serverName = "127.0.0.1";
    String functionName = SystemFunctionConstant.WORKFLOW_SCHEDULE;
    String errorMessage = "WorkflowTriggerScheduleJob.java -- ";
    
    try{
      this.dbConn = DataSourceFactory.getConnection();
      this.sessionContainer = new SessionContainer();
      UserRecordDAObject userDAO = new UserRecordDAObject(sessionContainer, dbConn);
      UserRecord userRecord = (UserRecord)userDAO.getObjectByID(new Integer(0));
      this.sessionContainer.setUserRecord(userRecord);
            
      /*************************************************************
       *  get Event Log Information Begin
       *************************************************************/
      if (!Utility.isEmpty(sessionContainer.getUserRecordID())) {
        trigerEventUserID = sessionContainer.getUserRecordID();
      }
      
      if (!Utility.isEmpty(sessionContainer.getUserIPAddress())) {        
        serverName = sessionContainer.getUserIPAddress();
      }      
//      errorMessage = " Track ID: " + currentProgress.getTrackID() + 
//                      ", Workflow Progress ID : " + currentProgress.getID() +
//                      ", Workflow Step ID: " + currentProgress.getWorkflowStepID() +
//                      "<br> ";
      /*************************************************************
       *  get Event Log Information End
       *************************************************************/      
      
      WorkflowScheduleTriggersDAObject triggerDAO = new WorkflowScheduleTriggersDAObject(this.sessionContainer,this.dbConn);
      WorkflowTriggersLogDAObject triggerLogDAO = new WorkflowTriggersLogDAObject(this.sessionContainer,this.dbConn);
      WorkflowScheduleTriggers workflowSchedule = (WorkflowScheduleTriggers)triggerDAO.getObjectByID(new Integer(objectID));
      
      Timestamp previousFireTime = null;
      Timestamp nextFireTime = null;
      String status = "";
      
      org.quartz.Scheduler sched = com.dcivision.framework.SchedulerFactory.getScheduler();
      org.quartz.Trigger trigger = sched.getTrigger ( GlobalConstant.JOB_PREFIX_WORKFLOW_SCHEDULE + workflowSchedule.getID(),
          GlobalConstant.JOB_PREFIX_WORKFLOW_SCHEDULE + "GROUP" );
      log.debug("=== Previous Fire Time : ===" + trigger.getPreviousFireTime());
      log.debug("=== Next Fire Time : ===" + trigger.getNextFireTime());
      boolean bUnscheduleJob = false;
      MaintWorkflowRecordForm recordForm = new MaintWorkflowRecordForm();
      if ( Utility.isEmpty(workflowSchedule.getRecurrMaxRun()) ||
          ( !Utility.isEmpty(workflowSchedule.getRecurrMaxRun()) && Utility.isEmpty(workflowSchedule.getRecurrRunCnt()) ) ||
          (( !Utility.isEmpty(workflowSchedule.getRecurrMaxRun()) && !Utility.isEmpty(workflowSchedule.getRecurrRunCnt()) )  &&
              ( workflowSchedule.getRecurrMaxRun().intValue() > workflowSchedule.getRecurrRunCnt().intValue() ) )
      ) {
        Integer trackID = null;
        
        try {
          boolean bTrigger = true;
          
          if ( !Utility.isEmpty(workflowSchedule.getCriteriaExpression()) ) {
            WorkflowTriggerCriteria criteria = (WorkflowTriggerCriteria )Class.forName(workflowSchedule.getCriteriaExpression()).newInstance();
            if ( !Utility.isEmpty(workflowSchedule.getCriteriaConfig()) ) {
              criteria.init(workflowSchedule.getCriteriaConfig());
            }
            bTrigger = criteria.validate();
          }
          bTrigger = true;
          log.debug("===== bTrigger =====" + bTrigger);
          //insert into trigger log with result = 0 or null
          trackID = new Integer(0);//simon_add
          //if ( bTrigger ) {//simon_del
            
            // Start a new Workflow
            WorkflowProgressManager manager = new WorkflowProgressManager(this.sessionContainer, this.dbConn);
            WorkflowRecordDAObject recordDAO = new WorkflowRecordDAObject(this.sessionContainer, this.dbConn);

            
            WorkflowRecord record = (WorkflowRecord) recordDAO.getObjectByID(workflowSchedule.getWorkflowRecordID());
            
            if ( !Utility.isEmpty(record) ) {
              recordForm.setFormData(record);
              //WorkflowProgress progress = (WorkflowProgress) manager.startWorkflowTrack(recordForm);//simon_del
              //trackID = progress.getTrackID();//simon_del
              //simon_add_S
              Timestamp currentDate=Utility.getCurrentTimestamp();
              Timestamp flowStartDate=record.getStartDate();
              Timestamp flowEndDate=record.getEndDate();
              if(!Utility.isEmpty(flowStartDate) && currentDate.compareTo(flowStartDate)>= 0){
            	if(Utility.isEmpty(flowEndDate) || currentDate.compareTo(flowEndDate)<= 0){
            	  log.debug("====== Start A Workflow =====");
            	  WorkflowProgress progress = (WorkflowProgress) manager.startWorkflowTrack(recordForm);
                  trackID = progress.getTrackID();
            	}else{
            	  //throw new ApplicationException("errors.eventlog.schedule_stoped");
            	  EventLogger.logEventMessageForSchedule(trigerEventUserID, serverName, MessageResourcesFactory.getMessage(sessionContainer.getSessionLocale(),"errors.eventlog.schedule_stoped", recordForm.getWorkflowCode()+recordForm.getWorkflowVersion(), recordForm.getEndDate()), WorkflowErrorConstant.LOG_SHCHEDULETRIGGER_CANCEL_CODE, functionName, recordForm.getID() );
            	}
              }else{
            	//throw new ApplicationException("errors.eventlog.schedule_stoped");
            	EventLogger.logEventMessageForSchedule(trigerEventUserID, serverName, MessageResourcesFactory.getMessage(sessionContainer.getSessionLocale(),"errors.eventlog.schedule_stoped", recordForm.getWorkflowCode()+recordForm.getWorkflowVersion(), recordForm.getEndDate()), WorkflowErrorConstant.LOG_SHCHEDULETRIGGER_CANCEL_CODE, functionName, recordForm.getID() );
              }
              //simon_add_E
            }
          //} else {//simon_del
            // insert into trigger log with result = 0 or null
            //trackID = new Integer(0);//simon_del
          //}simon_del
        } catch ( Exception ex ) {
          // insert into trigger log with result=-1
          log.debug(ex.toString());
          trackID = new Integer(-1);
        }
        //insert into trigger log with result = the new track_id
        WorkflowTriggersLog triggerLog = new WorkflowTriggersLog();
        triggerLog.setWorkflowTriggerID(workflowSchedule.getID());
        triggerLog.setWorkflowTrackID(trackID);
        log.debug("====== trackID: ========"+trackID);
        log.debug("====== Record the Wrokflow_Triggers_Log =====");
        triggerLogDAO.insertObject(triggerLog);
        status = WorkflowSchedule.SCHEDULE_TRIGGER_IN_PROGRESS_STATUS;
        
        // Unschedule the job if the maximum number of run is reached after this execution
        if ( !Utility.isEmpty(workflowSchedule.getRecurrMaxRun()) && workflowSchedule.getRecurrMaxRun().intValue()==1 ||
            (!Utility.isEmpty(workflowSchedule.getRecurrMaxRun()) && !Utility.isEmpty(workflowSchedule.getRecurrRunCnt())  &&
                workflowSchedule.getRecurrMaxRun().intValue() == workflowSchedule.getRecurrRunCnt().intValue()+1 )
        )
        {
          bUnscheduleJob = true;
        }
      } else {
        // It should not be here, but unschedule the job anyway
        log.debug ( "workflowSchedule.getRecurrRunCnt()="+workflowSchedule.getRecurrRunCnt());
        log.debug ( "workflowSchedule.getRecurrMaxRun()="+workflowSchedule.getRecurrMaxRun());
        bUnscheduleJob = true;
      }
      
      if ( bUnscheduleJob ) {
        //workflowSchedule stop Schedule;
        //org.quartz.Scheduler sched = com.dcivision.framework.SchedulerFactory.getScheduler(); ;
        sched.unscheduleJob( GlobalConstant.JOB_PREFIX_WORKFLOW_SCHEDULE + workflowSchedule.getID(),
            GlobalConstant.JOB_PREFIX_WORKFLOW_SCHEDULE + "GROUP" );
        status = WorkflowSchedule.SCHEDULE_TRIGGER_EXPIRE_STATUS;
      }
      
      // update the Previous Fire Time
      if ( !Utility.isEmpty(trigger.getPreviousFireTime()) ) {
        previousFireTime = new Timestamp(trigger.getPreviousFireTime().getTime());
      }
      
      // update the Next Fire Time
      if ( !Utility.isEmpty(trigger.getNextFireTime()) ) {
        if ( !Utility.isEmpty(workflowSchedule.getScheduleEnd()) && trigger.getNextFireTime().after(workflowSchedule.getScheduleEnd()) ){
          // The next fire time should be later than the schedule end time
          status =  WorkflowSchedule.SCHEDULE_TRIGGER_EXPIRE_STATUS;
        } else if ( !bUnscheduleJob ) {
          // The schedule is not expired yet
          nextFireTime = new Timestamp(trigger.getNextFireTime().getTime());
        }
      } else {
        status =  WorkflowSchedule.SCHEDULE_TRIGGER_EXPIRE_STATUS;
      }
      
      //update the Workflow_Schedule_Triggers
      if ( !Utility.isEmpty(previousFireTime) ){
        workflowSchedule.setPreviousFireTime(previousFireTime);
      }
      if ( !Utility.isEmpty(nextFireTime) ){
        workflowSchedule.setNextFireTime(nextFireTime);
      }
      
      if ( !Utility.isEmpty(status) ) {
        workflowSchedule.setStatus(status);
      }
      
      if( !Utility.isEmpty(workflowSchedule.getRecurrRunCnt()) ){
        workflowSchedule.setRecurrRunCnt( new Integer(workflowSchedule.getRecurrRunCnt().intValue() + 1) );
      } else {
        workflowSchedule.setRecurrRunCnt( new Integer(1) );
      }
      
      log.debug("===== Update Workflow_Schedule_Trigger ====="+workflowSchedule);
      if(!recordForm.getEndDate().equals("")){
          Timestamp tempTime = TextUtility.parseDBDateTimeToTimeStamp(recordForm.getEndDate());
          //if(trigger.getNextFireTime().getTime()>tempTime.getTime()){//simon_del
          if(!Utility.isEmpty(trigger.getNextFireTime()) && trigger.getNextFireTime().getTime()>tempTime.getTime()){//simon_add
              workflowSchedule.setNextFireTime(null);
              workflowSchedule.setStatus("C");
              triggerDAO.updateObject(workflowSchedule);
              sched.deleteJob(trigger.getJobName(), trigger.getJobGroup());  
              EventLogger.logEventMessageForSchedule(trigerEventUserID, serverName, MessageResourcesFactory.getMessage(sessionContainer.getSessionLocale(),"errors.eventlog.schedule_stoped", recordForm.getWorkflowCode()+recordForm.getWorkflowVersion(), recordForm.getEndDate()), WorkflowErrorConstant.LOG_SHCHEDULETRIGGER_CANCEL_CODE, functionName, recordForm.getID() );
          }  
	  }else{
          triggerDAO.updateObject(workflowSchedule);
      }

      this.dbConn.commit();
      
    }catch (ApplicationException appEx) {
      /***********************************
       *  Record the Event Log.
       ***********************************/
      EventLogger.logEventMessage(trigerEventUserID, serverName, errorMessage, appEx.getMsgCode(), WorkflowErrorConstant.LOG_SHCHEDULE_ERROR_CODE, functionName, appEx.toString() );
      
      log.error(appEx, appEx);
    }catch (Exception e) {
      // TODO: Workflow Exception Handling
      /***********************************
       *  Record the Event Log.
       ***********************************/
      EventLogger.logEventMessage(trigerEventUserID, serverName, errorMessage, ErrorConstant.COMMON_FATAL_ERROR, WorkflowErrorConstant.LOG_SHCHEDULE_ERROR_CODE, functionName, e.toString() );
      
      log.error(e, e);
    } finally {
      try { this.dbConn.close(); } catch (Exception ignore) {} finally { this.dbConn = null; }
    }
    log.debug("===================== Start A Workflow End. ============================");
  }
  
  
  
}

